package com.example.cloud.service.finance.impl;

import com.example.cloud.constants.StateConstants;
import com.example.cloud.dao.basic.info.MemberDiscountProductCategoryRepository;
import com.example.cloud.dao.basic.info.MemberDiscountProductRepository;
import com.example.cloud.dao.basic.info.MemberDiscountProjectRepository;
import com.example.cloud.dao.basic.info.MemberDiscountProjectTypeRepository;
import com.example.cloud.dao.basic.info.MemberDiscountRepository;
import com.example.cloud.dao.finance.ChargeDetailsRepository;
import com.example.cloud.dao.mongdb.basic.info.MongoProductRepository;
import com.example.cloud.dao.mongdb.basic.info.MongoProjectRepository;
import com.example.cloud.model.basic.Product;
import com.example.cloud.model.basic.Project;
import com.example.cloud.model.finance.ChargeDetails;
import com.example.cloud.model.finance.ConsumeDiscount;
import com.example.cloud.model.member.Member;
import com.example.cloud.model.member.MemberDiscount;
import com.example.cloud.model.member.MemberDiscountProduct;
import com.example.cloud.model.member.MemberDiscountProductCategory;
import com.example.cloud.model.member.MemberDiscountProject;
import com.example.cloud.model.member.MemberDiscountProjectType;
import com.example.cloud.service.basic.info.MemberDiscountService;
import com.example.cloud.service.basic.info.MemberService;
import com.example.cloud.service.finance.ChargeDetailsService;
import com.example.cloud.utils.BusinessUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;

/**
 * Created by wangtao on 2018/5/22.
 */
@Service
public class ChargeDetailsServiceImpl implements ChargeDetailsService {

    @PersistenceContext
    EntityManager em;

    @Autowired
    private ChargeDetailsRepository chargeDetailsRepository;

    @Autowired
    private MemberService memberService;

    @Autowired
    private MongoProductRepository mongoProductRepository;

    @Autowired
    private MongoProjectRepository mongoProjectRepository;

    @Autowired
    private MemberDiscountService memberDiscountService;

    @Autowired
    private MemberDiscountRepository memberDiscountRepository;

    @Autowired
    private MemberDiscountProductRepository memberDiscountProductRepository;

    @Autowired
    private MemberDiscountProductCategoryRepository memberDiscountProductCategoryRepository;

    @Autowired
    private MemberDiscountProjectRepository memberDiscountProjectRepository;

    @Autowired
    private MemberDiscountProjectTypeRepository memberDiscountProjectTypeRepository;

    @Override
    @Transactional
    public ChargeDetails saveOrUpdate(ChargeDetails record) {
        BusinessUtil.appendRecord(record);
        return chargeDetailsRepository.save(record);
    }

    @Override
    public Map<String, Object> doMatchDiscount(List<ChargeDetails> records) {
        Map<String, Object> resultMap = new HashMap<>();
        // 最终返回匹配成功后的数据
        List<ChargeDetails> list = new ArrayList<>();
        // 最终使用到的折扣
        List<ConsumeDiscount> discounts = new ArrayList<>();
        // 用来过滤重复的折扣
        Map<String, ConsumeDiscount> discountMap = new HashMap<>();
        // 分为打折商品和不打折商品
        Member member = memberService.findOne(records.get(0).getMemberId());
        if (member != null) {
            // 家庭病房和外科手术不打折
            list.addAll(records.stream().filter((ChargeDetails chargeDetails) -> chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_HOME || chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_SURGICAL).collect(toList()));
            // 只有单次收费和长期收费可以使用折扣,抽出对应数据
            List<ChargeDetails> list1 = records.stream().filter((ChargeDetails chargeDetails) -> chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_ONE).collect(toList());
            // 单次收费商品中只取项目和非药品
            List<ChargeDetails> list2 = new ArrayList<>();
            list1.forEach(chargeDetails -> {
                if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                    Long productId = chargeDetails.getItemId();
                    Product product = mongoProductRepository.findOne(productId);
                    // 只取非药品
                    if (product.getIsDrug() == StateConstants.PRODUCT_IS_DRUG_NO) {
                        list2.add(chargeDetails);
                    } else {
                        // 药品类加入不打折商品
                        list.add(chargeDetails);
                    }
                } else {
                    // 项目类
                    list2.add(chargeDetails);
                }
            });
            // 长期收费商品
            List<ChargeDetails> list3 = records.stream().filter((ChargeDetails chargeDetails) -> chargeDetails.getBusinessType() == StateConstants.CHARGE_BUSINESS_TYPE_COURSE).collect(toList());
            // 长期收费商品包括疗程和医药产品,其中只有医学护肤品能够享受折扣,取出医药产品
            // 疗程加入到不打折商品中
            list.addAll(list3.stream().filter((ChargeDetails chargeDetails) -> chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_COURSE).collect(toList()));
            // 医药产品
            List<ChargeDetails> list4 = list3.stream().filter((ChargeDetails chargeDetails) -> chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT).collect(toList());
            // 从医药产品中取出非药品
            list4.forEach(chargeDetails -> {
                Long productId = chargeDetails.getItemId();
                Product product = mongoProductRepository.findOne(productId);
                // 只取非药品
                if (product.getIsDrug() == StateConstants.PRODUCT_IS_DRUG_NO) {
                    list2.add(chargeDetails);
                } else {
                    // 药品加入不打折商品
                    list.add(chargeDetails);
                }
            });
            // 到此，打折商品提取完成
            // 先获取该会员对应的所有折扣
            // 会员折扣
            MemberDiscount memberDiscount = memberDiscountRepository.findByMemberIdAndDeleteFlag(member.getId(), 0);
            // 产品类折扣
            List<MemberDiscountProductCategory> discountList1 = memberDiscountProductCategoryRepository.findByMemberIdAndExpired(member.getId(), 0);
            // 产品大类折扣
            List<MemberDiscountProductCategory> bigClassDiscount = discountList1.stream().filter(discountProductCategory -> discountProductCategory.getCategoryType() == StateConstants.CATEGORY_TYPE_BIG).collect(toList());
            // 产品小类折扣
            List<MemberDiscountProductCategory> smallClassDiscount = discountList1.stream().filter(discountProductCategory -> discountProductCategory.getCategoryType() == StateConstants.CATEGORY_TYPE_SMALL).collect(toList());
            // 产品折扣
            List<MemberDiscountProduct> discountList2 = memberDiscountProductRepository.findByMemberIdAndExpired(member.getId(), 0);
            // 项目类折扣
            List<MemberDiscountProjectType> discountList3 = memberDiscountProjectTypeRepository.findByMemberIdAndExpired(member.getId(), 0);
            // 项目折扣
            List<MemberDiscountProject> discountList4 = memberDiscountProjectRepository.findByMemberIdAndExpired(member.getId(), 0);
            // 筛选出产品折扣
            Map<Long, List<ConsumeDiscount>> detailsListMap1 = new HashMap<>();
            // 筛选出项目折扣
            Map<Long, List<ConsumeDiscount>> detailsListMap2 = new HashMap<>();
            // 为每个可享受折扣的商品添加会员折扣
            if (memberDiscount != null) {
                list2.forEach(chargeDetails -> {
                    Long itemId = chargeDetails.getItemId();
                    // 如果是产品
                    if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PROJECT) {
                        if (!detailsListMap1.containsKey(itemId)) {
                            List<ConsumeDiscount> discountList = new ArrayList<>();
                            ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                            consumeDiscount.setDiscount(memberDiscount.getDiscount());
                            consumeDiscount.setDiscountName(memberDiscount.getDiscountName());
                            discountList.add(consumeDiscount);
                            detailsListMap1.put(itemId, discountList);
                        }
                    } else if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                        if (!detailsListMap2.containsKey(itemId)) {
                            List<ConsumeDiscount> discountList = new ArrayList<>();
                            ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                            consumeDiscount.setDiscount(memberDiscount.getDiscount());
                            consumeDiscount.setDiscountName(memberDiscount.getDiscountName());
                            discountList.add(consumeDiscount);
                            detailsListMap2.put(itemId, discountList);
                        }
                    }
                });
            }
            list2.forEach(chargeDetails -> {
                // 如果是产品
                if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PROJECT) {
                    Long productId = chargeDetails.getItemId();
                    Product product = mongoProductRepository.findOne(productId);
                    for (MemberDiscountProductCategory discount : bigClassDiscount) {
                        // 匹配到折扣
                        if (discount.getCategoryId().equals(product.getBigClassId())) {
                            if (detailsListMap1.containsKey(productId)) {
                                ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                consumeDiscount.setDiscount(discount.getDiscount());
                                consumeDiscount.setDiscountName(discount.getDiscountName());
                                consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                detailsListMap1.get(productId).add(consumeDiscount);
                            } else {
                                List<ConsumeDiscount> discountList = new ArrayList<>();
                                ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                consumeDiscount.setDiscount(discount.getDiscount());
                                consumeDiscount.setDiscountName(discount.getDiscountName());
                                consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                discountList.add(consumeDiscount);
                                detailsListMap1.put(productId, discountList);
                            }
                        }
                    }
                    // 匹配折扣小类
                    if (detailsListMap1.size() > 0) {
                        for (Map.Entry<Long, List<ConsumeDiscount>> entry : detailsListMap1.entrySet()) {
                            productId = entry.getKey();
                            product = mongoProductRepository.findOne(productId);
                            for (MemberDiscountProductCategory discount : smallClassDiscount) {
                                if (discount.getCategoryId().equals(product.getSmallClassId())) {
                                    if (detailsListMap1.containsKey(productId)) {
                                        ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                        consumeDiscount.setDiscount(discount.getDiscount());
                                        consumeDiscount.setDiscountName(discount.getDiscountName());
                                        consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                        detailsListMap1.get(productId).add(consumeDiscount);
                                    } else {
                                        List<ConsumeDiscount> discountList = new ArrayList<>();
                                        ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                        consumeDiscount.setDiscount(discount.getDiscount());
                                        consumeDiscount.setDiscountName(discount.getDiscountName());
                                        consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                        discountList.add(consumeDiscount);
                                        detailsListMap1.put(productId, discountList);
                                    }
                                }
                            }
                        }
                    }
                    // 匹配具体商品
                    if (detailsListMap1.size() > 0) {
                        for (Map.Entry<Long, List<ConsumeDiscount>> entry : detailsListMap1.entrySet()) {
                            productId = entry.getKey();
                            for (MemberDiscountProduct discount : discountList2) {
                                if (discount.getProductId().equals(productId)) {
                                    if (detailsListMap1.containsKey(productId)) {
                                        ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                        consumeDiscount.setDiscount(discount.getDiscount());
                                        consumeDiscount.setDiscountName(discount.getDiscountName());
                                        consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                        detailsListMap1.get(productId).add(consumeDiscount);
                                    } else {
                                        List<ConsumeDiscount> discountList = new ArrayList<>();
                                        ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                        consumeDiscount.setDiscount(discount.getDiscount());
                                        consumeDiscount.setDiscountName(discount.getDiscountName());
                                        consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                        discountList.add(consumeDiscount);
                                        detailsListMap1.put(productId, discountList);
                                    }
                                }
                            }
                        }
                    }
                } else if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                    Long projectId = chargeDetails.getItemId();
                    Project project = mongoProjectRepository.findOne(projectId);
                    for (MemberDiscountProjectType discount : discountList3) {
                        if (discount.getProjectTypeId().equals(project.getProjectTypeId())) {
                            if (detailsListMap2.containsKey(projectId)) {
                                ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                consumeDiscount.setDiscount(discount.getDiscount());
                                consumeDiscount.setDiscountName(discount.getDiscountName());
                                consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                detailsListMap2.get(projectId).add(consumeDiscount);
                            } else {
                                List<ConsumeDiscount> discountList = new ArrayList<>();
                                ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                consumeDiscount.setDiscount(discount.getDiscount());
                                consumeDiscount.setDiscountName(discount.getDiscountName());
                                consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                discountList.add(consumeDiscount);
                                detailsListMap2.put(projectId, discountList);
                            }
                        }
                    }
                    if (detailsListMap2.size() > 0) {
                        for (Map.Entry<Long, List<ConsumeDiscount>> entry : detailsListMap2.entrySet()) {
                            projectId = entry.getKey();
                            project = mongoProjectRepository.findOne(projectId);
                            for (MemberDiscountProject discount : discountList4) {
                                if (discount.getProjectId().equals(projectId)) {
                                    if (detailsListMap2.containsKey(projectId)) {
                                        ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                        consumeDiscount.setDiscount(discount.getDiscount());
                                        consumeDiscount.setDiscountName(discount.getDiscountName());
                                        consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                        detailsListMap2.get(projectId).add(consumeDiscount);
                                    } else {
                                        List<ConsumeDiscount> discountList = new ArrayList<>();
                                        ConsumeDiscount consumeDiscount = new ConsumeDiscount();
                                        consumeDiscount.setDiscount(discount.getDiscount());
                                        consumeDiscount.setDiscountName(discount.getDiscountName());
                                        consumeDiscount.setDiscountDesc(discount.getDiscountDesc());
                                        discountList.add(consumeDiscount);
                                        detailsListMap2.put(projectId, discountList);
                                    }
                                }
                            }
                        }
                    }
                }
            });
            // 到此项目和产品的折扣已经匹配出来
            // 优选折扣，选择折扣率最低的
            // 产品折扣
            Map<Long, ConsumeDiscount> consumeDiscountMap1 = new HashMap<>();
            for (Map.Entry<Long, List<ConsumeDiscount>> entry : detailsListMap1.entrySet()) {
                Long productId = entry.getKey();
                List<ConsumeDiscount> discountList = entry.getValue();
                // 按折扣排序
                discountList.sort((d1, d2) -> d2.getDiscount().compareTo(d1.getDiscount()));
                ConsumeDiscount consumeDiscount = discountList.get(0);
                // 取出最高折扣
                consumeDiscountMap1.put(productId, consumeDiscount);
                // 记录用到的折扣
                if(!discountMap.containsKey(consumeDiscount.getDiscountName())){
                    discountMap.put(consumeDiscount.getDiscountName(), consumeDiscount);
                }
            }
            // 项目折扣
            Map<Long, ConsumeDiscount> consumeDiscountMap2 = new HashMap<>();
            for (Map.Entry<Long, List<ConsumeDiscount>> entry : detailsListMap2.entrySet()) {
                Long projectId = entry.getKey();
                List<ConsumeDiscount> discountList = entry.getValue();
                // 按折扣排序
                discountList.sort((d1, d2) -> d2.getDiscount().compareTo(d1.getDiscount()));
                ConsumeDiscount consumeDiscount = discountList.get(0);
                consumeDiscountMap2.put(projectId, consumeDiscount);
                // 记录用到的折扣
                if(!discountMap.containsKey(consumeDiscount.getDiscountName())){
                    discountMap.put(consumeDiscount.getDiscountName(), consumeDiscount);
                }
            }
            // 到此已经筛选出最高折扣
            // 应用折扣
            list2.forEach(chargeDetails -> {
                // 如果是产品
                if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PROJECT) {
                    Long productId = chargeDetails.getItemId();
                    if (consumeDiscountMap1.containsKey(productId)) {
                        ConsumeDiscount consumeDiscount = consumeDiscountMap1.get(productId);
                        chargeDetails.setDiscount(consumeDiscount.getDiscount());
                        // 应付金额 * 折扣 = 实付金额
                        BigDecimal actualAmount = chargeDetails.getTotalPrice().multiply(new BigDecimal(consumeDiscount.getDiscount()));
                        chargeDetails.setActualAmount(actualAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
                        // 应付金额 - 实付金额 = 优惠金额
                        BigDecimal discountAmount = chargeDetails.getTotalPrice().subtract(chargeDetails.getActualAmount());
                        chargeDetails.setDiscountAmount(discountAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
                    }
                } else if (chargeDetails.getChargeType() == StateConstants.CHARGE_CHARGE_TYPE_PRODUCT) {
                    Long projectId = chargeDetails.getItemId();
                    if (consumeDiscountMap2.containsKey(projectId)) {
                        ConsumeDiscount consumeDiscount = consumeDiscountMap2.get(projectId);
                        chargeDetails.setDiscount(consumeDiscount.getDiscount());
                        // 应付金额 * 折扣 = 实付金额
                        BigDecimal actualAmount = chargeDetails.getTotalPrice().multiply(new BigDecimal(consumeDiscount.getDiscount()));
                        chargeDetails.setActualAmount(actualAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
                        // 应付金额 - 实付金额 = 优惠金额
                        BigDecimal discountAmount = chargeDetails.getTotalPrice().subtract(chargeDetails.getActualAmount());
                        chargeDetails.setDiscountAmount(discountAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
                    }
                }
            });
            // 到此折扣计算完成，返回计算后的数据
            list.addAll(list2);
        }
        // 返回使用的折扣
        if(!discountMap.isEmpty()){
            for (ConsumeDiscount consumeDiscount : discountMap.values()) {
                discounts.add(consumeDiscount);
            }
        }
        resultMap.put("data", list);
        resultMap.put("discount", discounts);
        return resultMap;
    }
}
